package com.dog.basics.service.mtkj.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Validator;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dog.basics.bean.dto.admin.mtkj.AdminShopBlEditDto;
import com.dog.basics.bean.dto.admin.mtkj.ShopListDto;
import com.dog.basics.bean.dto.api.mtkj.ApiShopAddDto;
import com.dog.basics.bean.dto.api.mtkj.ApiShopEditDto;
import com.dog.basics.bean.dto.api.mtkj.ApiShopFromDto;
import com.dog.basics.bean.dto.api.mtkj.ApiShopListDto;
import com.dog.basics.bean.model.common.DogUser;
import com.dog.basics.bean.model.mtkj.MtGoods;
import com.dog.basics.bean.model.mtkj.MtShopGoodType;
import com.dog.basics.bean.model.mtkj.MtShopping;
import com.dog.basics.bean.model.mtkj.MtShoppingAccount;
import com.dog.basics.bean.vo.admin.mtkj.ShopListVo;
import com.dog.basics.bean.vo.admin.mtkj.ShoppingVo;
import com.dog.basics.bean.vo.api.mtkj.ApiAddShopingCheckVo;
import com.dog.basics.bean.vo.api.mtkj.ApiShoppingFromVo;
import com.dog.basics.bean.vo.api.mtkj.ApiShoppingVo;
import com.dog.basics.common.util.PageParam;
import com.dog.basics.dao.common.DogUserMapper;
import com.dog.basics.dao.mtkj.MtGoodsMapper;
import com.dog.basics.dao.mtkj.MtShopGoodTypeMapper;
import com.dog.basics.dao.mtkj.MtShoppingAccountMapper;
import com.dog.basics.dao.mtkj.MtShoppingMapper;
import com.dog.basics.security.util.SecurityUtils;
import com.dog.basics.service.mtkj.IMtShoppingService;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 店铺信息 服务实现类
 * </p>
 *
 * @author wph
 * @since 2020-11-09
 */
@Service
@AllArgsConstructor
public class MtShoppingServiceImpl extends ServiceImpl<MtShoppingMapper, MtShopping> implements IMtShoppingService {
    private final MtShoppingAccountMapper shoppingAccountMapper;
    private final DogUserMapper userMapper;
    private final MtGoodsMapper goodsMapper;
    private final MtShopGoodTypeMapper shopGoodTypeMapper;

    /**
     * 根据id获取商铺信息
     * 如果未查询到信息返回null
     *
     * @param id
     * @return
     * @author hangdy
     */
    @Override
    public ApiShoppingVo findShoppingById(Long id) {
        ApiShoppingVo apiShoppingVo = new ApiShoppingVo();
        MtShopping shopping = this.getById(id);
        //查询用户名 目前保存的是昵称
        DogUser user = userMapper.selectById(shopping.getUserId());

        apiShoppingVo.setUserName(ObjectUtil.isNotNull(user) ? user.getNickName() : "");
        //查询用户名 目前保存的是昵称
        BeanUtil.copyProperties(shopping, apiShoppingVo);

        return apiShoppingVo;
    }

    /**
     * 根据用户id 查询店铺信息
     *
     * @param: userId
     * @returns
     * @author hangdy
     * @date: 2020/11/20 15:48
     */
    @Override
    public ApiShoppingVo findShoppingByUserId(Long userId) {
        Validator.validateNotNull(userId, "用户id不能为空");

        ApiShoppingVo apiShoppingVo = new ApiShoppingVo();
        List<MtShopping> shoppings = this.list(Wrappers.<MtShopping>lambdaQuery().eq(MtShopping::getUserId, userId).eq(MtShopping::getStatus, 1));
        Validator.validateTrue(ObjectUtil.isNotNull(shoppings), "商铺信息不存在");
        Validator.validateTrue(shoppings.size() > 0, "商铺信息不存在");

        //查询用户名 目前保存的是昵称
        DogUser user = userMapper.selectById(shoppings.get(0).getUserId());
        apiShoppingVo.setUserName(ObjectUtil.isNotNull(user) ? user.getNickName() : "");
        //查询用户名 目前保存的是昵称
        BeanUtil.copyProperties(shoppings.get(0), apiShoppingVo);
        apiShoppingVo.setPayPassword(user.getPayPassword());
        return apiShoppingVo;
    }

    /**
     * 搜索商铺
     * 1.根据商铺名称进行搜索 并支持排序
     *
     * @param: page
     * @param: shopListDto
     * @returns
     * @author hangdy
     * @date: 2020/11/12 10:41
     */
    @Override
    public IPage<ApiShoppingFromVo> getPageList(PageParam page, ApiShopListDto shopListDto, boolean needStatus, Integer status) {
        IPage iPage = this.page(page, Wrappers.<MtShopping>lambdaQuery()
                        .eq(needStatus, MtShopping::getStatus, status)
                        .like(ObjectUtil.isNotNull(shopListDto.getShopName()), MtShopping::getName, shopListDto.getShopName())
                //排序使用
                //    .orderBy(!shopListDto.getOrderBySalesIsNull(), shopListDto.getIsOrderBySales(), MtShopping::getSales)
                //     .orderBy(!shopListDto.getIsOrderBystars(), shopListDto.getIsOrderBystars(), MtShopping::getSales)
                //    .orderBy(!shopListDto.getOrderByCrtTimeIsNull(), shopListDto.getIsOrderByCrtTime(), MtShopping::getCreateTime)
                //排序使用
        );
        List<MtShopping> shoppingList = iPage.getRecords();

        iPage.setRecords(shoppingList.stream().map(e -> BeanUtil.copyProperties(e, ApiShoppingFromVo.class)).collect(Collectors.toList()));

        return iPage;
    }

    /**
     * 查询附近商铺
     *
     * @param page
     * @param shopFromDto
     * @return
     * @author hangdy
     */
    @Override
    public IPage<ApiShoppingFromVo> nearbyShops(PageParam page, ApiShopFromDto shopFromDto) {
        String limit = " order By create_time desc";
        if (ObjectUtil.isNotNull(shopFromDto.getSales())) {
            if (shopFromDto.getSales() == 0) {
                limit = " order By sales desc";
            } else {
                limit = " order By sales asc";
            }
        }
        if (ObjectUtil.isNotNull(shopFromDto.getStars())) {
            if (shopFromDto.getStars() == 0) {
                limit = " order By stars desc";
            } else {
                limit = " order By stars asc";
            }
        }
        List<Double> list = findNeighPosition(shopFromDto.getLongitude().doubleValue(), shopFromDto.getLatitude().doubleValue(), shopFromDto.getDistance());

        IPage apiShoppingFromVoIPage = this.page(page, Wrappers.<MtShopping>lambdaQuery()
                .like(ObjectUtil.isNotNull(shopFromDto.getName()), MtShopping::getName, shopFromDto.getName())
                .ge(MtShopping::getLatitude, list.get(0))
                .le(MtShopping::getLatitude, list.get(1))
                .ge(MtShopping::getLongitude, list.get(2))
                .le(MtShopping::getLongitude, list.get(3))
                .eq(MtShopping::getDelFlag, 0)
                //排序使用
                .last(limit)
        );
        List<MtShopping> shoppingList = apiShoppingFromVoIPage.getRecords();
        List<ApiShoppingFromVo> fromVoList = new ArrayList<>();
        fromVoList = shoppingList.stream().map(e -> {
            ApiShoppingFromVo vo = BeanUtil.copyProperties(e, ApiShoppingFromVo.class);
            vo.setJuli(getDistance(e.getLatitude().doubleValue(), e.getLongitude().doubleValue(), shopFromDto.getLatitude().doubleValue(), shopFromDto.getLongitude().doubleValue()));
            return vo;
        }).collect(Collectors.toList());
        apiShoppingFromVoIPage.setRecords(fromVoList);
        return apiShoppingFromVoIPage;
    }


    /**
     * 新增商铺信息
     *
     * @param shopAddDto
     * @return
     * @author hangdy
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean saveShop(ApiShopAddDto shopAddDto) {
        //判断是否已有商铺
        List<MtShopping> shoppingList = this.list(Wrappers.<MtShopping>lambdaQuery().eq(MtShopping::getUserId, SecurityUtils.getUser().getUserId()).orderByDesc(MtShopping::getCreateTime));
        if (shoppingList.size() != 0) {
            MtShopping mtShopping = shoppingList.get(0);
            if (mtShopping.getStatus() == 0) {
                Validator.validateTrue(Boolean.FALSE, "您的店铺申请未审核!");

            } else if (mtShopping.getStatus() == 1) {
                Validator.validateTrue(Boolean.FALSE, "已存在商铺不能申请");
            }

        }

        MtShopping shopping = new MtShopping();
        BeanUtil.copyProperties(shopAddDto, shopping);
        shopping.setUserId(SecurityUtils.getUser().getUserId());
        shopping.setCreateTime(DateUtil.currentSeconds());
        shopping.setCreateUser(SecurityUtils.getUser().getUserId());
        shopping.setDelFlag(0);
        shopping.setStatus(0);
        Validator.validateTrue(this.save(shopping), "商铺信息新增失败");

        //添加商铺账户表信息  start
        //保存 商铺id 账户金额0 冻结金额0
        MtShoppingAccount shoppingAccount = new MtShoppingAccount();
        shoppingAccount.setShopId(shopping.getId());
        shoppingAccount.setMoney(new BigDecimal(0));
        shoppingAccount.setFreezingMoney(new BigDecimal(0));

        shoppingAccount.setCreateTime(DateUtil.currentSeconds());
        shoppingAccount.setCreateBy(SecurityUtils.getUser().getUserId());
        Validator.validateTrue(retBool(shoppingAccountMapper.insert(shoppingAccount)), "商铺账户创建失败");
        //添加商铺账户表信息 end
        return Boolean.TRUE;
    }

    /**
     * 修改商铺信息
     *
     * @param shopEditDto
     * @return
     * @author hangdy
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean editShop(ApiShopEditDto shopEditDto) {
        MtShopping shopping = this.getById(shopEditDto.getId());
        Validator.validateNotNull(shopping, "未找到商铺信息");

        //判断是否属于该用户
        Validator.validateEqual(shopping.getUserId(), SecurityUtils.getUser().getUserId(), "商铺信息有误");

        BeanUtil.copyProperties(shopEditDto, shopping);
        shopping.setUpdateTime(DateUtil.currentSeconds());
        shopping.setUpdateUser(SecurityUtils.getUser().getUserId());
        Validator.validateTrue(this.updateById(shopping), "商铺信息更新失败!");
        return Boolean.TRUE;
    }

    /**
     * 删除店铺
     *
     * @param id
     * @return
     * @author hangdy
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean deleteShop(Long id) {
        MtShopping shopping = this.getById(id);
        Validator.validateNotNull(shopping, "无此数据");
        List<MtGoods> goodsList = goodsMapper.selectList(Wrappers.<MtGoods>lambdaQuery().eq(MtGoods::getShopId, shopping.getId()));
        Validator.validateTrue(goodsList.size() == 0, "商铺关联有商品不能删除");
        List<MtShopGoodType> shopGoodTypeList = shopGoodTypeMapper.selectList(Wrappers.<MtShopGoodType>lambdaQuery().eq(MtShopGoodType::getShopId, shopping.getId()));
        Validator.validateTrue(shopGoodTypeList.size() == 0, "商铺关联有商品类别不能删除");
        //判断是否属于该用户
        Validator.validateEqual(shopping.getUserId(), SecurityUtils.getUser().getUserId(), "商铺信息有误");

        Validator.validateTrue(this.removeById(id), "删除店铺失败!");
        return Boolean.TRUE;
    }

    /**
     * 保存收款二维码地址
     *
     * @param shopId
     * @param url
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean upQRCode(Long shopId, String url) {
        MtShopping shopping = this.getById(shopId);
        Validator.validateNotNull(shopping, "未找到商铺信息");
        //判断是否属于该用户
        Validator.validateEqual(shopping.getUserId(), SecurityUtils.getUser().getUserId(), "商铺信息有误");
        //判断url是否五空
        Validator.validateNotNull(url, "收款码地址不能为空");

        shopping.setWxPayUrl(url);
        Validator.validateTrue(this.save(shopping), "商铺信息新增失败");
        return Boolean.TRUE;
    }

    /**
     * admin服务
     * 审核店铺
     *
     * @param shopId
     * @param checkStatus
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean checkShop(Long shopId, Integer checkStatus) {


        MtShopping shopping = this.getById(shopId);
        Validator.validateNotNull(shopping, "未找到商铺信息");
        Validator.validateNotNull(checkStatus, "审核状态不能为空");

        Validator.validateEqual(shopping.getStatus(), 0, "未审核状态才能审核");

        shopping.setStatus(checkStatus);

        Validator.validateTrue(this.updateById(shopping), "审核商铺失败");
        return Boolean.TRUE;
    }

    /**
     * 修改店铺分润比例
     *
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean editObj(AdminShopBlEditDto obj) {
        MtShopping shopping = this.getById(obj.getId());
        Validator.validateNotNull(shopping, "未找到商铺信息");
        shopping.setBl(obj.getBl());
        Validator.validateTrue(this.updateById(shopping), "修改店铺分润比例失败");
        return Boolean.TRUE;
    }

    /**
     * 判断用户是否有店铺
     *
     * @param:
     * @returns
     * @author hangdy
     * @date: 2020/11/20 10:51
     */
    @Override
    public ApiAddShopingCheckVo checkUserAddShop() {
        List<MtShopping> shoppingList = this.list(Wrappers.<MtShopping>lambdaQuery().eq(MtShopping::getUserId, SecurityUtils.getUser().getUserId()).orderByDesc(MtShopping::getCreateTime));
        ApiAddShopingCheckVo vo = new ApiAddShopingCheckVo();
        if (CollUtil.isNotEmpty(shoppingList)) {
            MtShopping mtShopping = shoppingList.get(0);
            if (mtShopping.getStatus() == 0) {
                vo.setStatus(0);
                vo.setShopStatus(shoppingList.get(0).getStatus());
                vo.setMsg("商铺还未审核");
            } else if (mtShopping.getStatus() == 1) {
                vo.setStatus(0);
                vo.setShopStatus(shoppingList.get(0).getStatus());
                vo.setMsg("已有商铺");
            } else {
                vo.setStatus(1);
                vo.setShopStatus(shoppingList.get(0).getStatus());
                vo.setMsg("商铺申请拒绝");
            }


            return vo;
        }
        vo.setStatus(1);
        return vo;
    }


    /**
     * admin服务
     * 查询店铺信息
     *
     * @param page
     * @param dto
     * @return
     */
    @Override
    public IPage<ShopListVo> findShopByAdmin(PageParam page, ShopListDto dto) {


        IPage iPage = this.page(page, Wrappers.<MtShopping>lambdaQuery()

                        .eq(ObjectUtil.isNotNull(dto.getStars()), MtShopping::getStars, dto.getStars())
                        .eq(ObjectUtil.isNotNull(dto.getStatus()), MtShopping::getStatus, dto.getStatus())

                        .like(ObjectUtil.isNotNull(dto.getRealName()), MtShopping::getRealName, dto.getRealName())
                        .like(ObjectUtil.isNotNull(dto.getName()), MtShopping::getName, dto.getName())
                        .like(ObjectUtil.isNotNull(dto.getMobile()), MtShopping::getMobile, dto.getMobile())
                        .like(ObjectUtil.isNotNull(dto.getShopAddress()), MtShopping::getShopAddress, dto.getShopAddress())
                        .like(ObjectUtil.isNotNull(dto.getPickAddress()), MtShopping::getPickAddress, dto.getPickAddress())
                        //排序使用
                        .orderBy(!dto.getOrderBySalesIsNull(), dto.getIsOrderBySales(), MtShopping::getSales)
                        .orderBy(!dto.getIsOrderBystars(), dto.getIsOrderBystars(), MtShopping::getSales)
                        .orderBy(!dto.getOrderByCrtTimeIsNull(), dto.getIsOrderByCrtTime(), MtShopping::getCreateTime)
                //排序使用
        );
        List<MtShopping> shoppingList = iPage.getRecords();

        List<ShopListVo> shopListVoList = shoppingList.stream().map(e -> {
            ShopListVo vo = BeanUtil.copyProperties(e, ShopListVo.class);

            //设置所属用户
            DogUser user = userMapper.selectById(e.getUserId());
            if (user != null) {
                vo.setUserName(ObjectUtil.isNotNull(user.getNickName()) ? user.getNickName() : "");
            }
            //设置创建用户
            DogUser creUser = userMapper.selectById(e.getCreateUser());
            if (creUser != null) {
                vo.setCreateUser(ObjectUtil.isNotNull(creUser.getNickName()) ? creUser.getNickName() : "");
            }

            //设置修改用户
            DogUser upUser = userMapper.selectById(e.getUpdateUser());
            if (upUser != null) {
                vo.setCreateUser(ObjectUtil.isNotNull(upUser.getNickName()) ? upUser.getNickName() : "");
            }

            return vo;
        }).collect(Collectors.toList());

        iPage.setRecords(shopListVoList);

        return iPage;

    }

    /**
     * admin服务
     * 获取店铺详情
     *
     * @param: id
     * @returns
     * @author hangdy
     * @date: 2020/11/14 12:02
     */
    @Override
    public ShoppingVo adminShippingById(Long id) {
        ShoppingVo shoppingVo = new ShoppingVo();
        MtShopping shopping = this.getById(id);

        BeanUtil.copyProperties(shopping, shoppingVo);

        //查询用户名 目前保存的是昵称
        DogUser user = userMapper.selectById(shopping.getUserId());

        shoppingVo.setUserName(ObjectUtil.isNotNull(user) ? user.getNickName() : "");
        //查询创建用户
        DogUser crtUser = userMapper.selectById(shopping.getCreateUser());
        shoppingVo.setCreateUser(ObjectUtil.isNotNull(crtUser) ? crtUser.getNickName() : "");
        //查询修改用户
        DogUser updUser = userMapper.selectById(shopping.getUpdateUser());
        shoppingVo.setCreateUser(ObjectUtil.isNotNull(updUser) ? updUser.getNickName() : "");

        return shoppingVo;
    }

    /**
     * admin服务
     * 超级管理员删除店铺
     *
     * @param id
     * @return
     */
    @Override
    public Boolean adminDeleteShop(Long id) {

        //查询商品是否存在
        MtShopping shopping = this.getById(id);
        Validator.validateNotNull(shopping, "无此数据");
        List<MtGoods> goodsList = goodsMapper.selectList(Wrappers.<MtGoods>lambdaQuery().eq(MtGoods::getShopId, shopping.getId()));
        Validator.validateFalse(CollUtil.isNotEmpty(goodsList), "店铺下有商品不能删除!");

        Validator.validateTrue(this.removeById(id), "删除店铺失败!");

        return Boolean.TRUE;
    }


    /**
     * 通过经纬度计算距离
     *
     * @param lat1
     * @param lng1
     * @param lat2
     * @param lng2
     * @return
     */
    private double getDistance(Double lat1, Double lng1, Double lat2, Double lng2) {
        double EARTH_RADIUS = 6371393;
        // 经纬度（角度）转弧度。弧度用作参数，以调用Math.cos和Math.sin
        double radiansAX = Math.toRadians(lng1); // A经弧度
        double radiansAY = Math.toRadians(lat1); // A纬弧度
        double radiansBX = Math.toRadians(lng2); // B经弧度
        double radiansBY = Math.toRadians(lat2); // B纬弧度

        // 公式中“cosβ1cosβ2cos（α1-α2）+sinβ1sinβ2”的部分，得到∠AOB的cos值
        double cos = Math.cos(radiansAY) * Math.cos(radiansBY) * Math.cos(radiansAX - radiansBX)
                + Math.sin(radiansAY) * Math.sin(radiansBY);
//        System.out.println("cos = " + cos); // 值域[-1,1]
        double acos = Math.acos(cos); // 反余弦值
//        System.out.println("acos = " + acos); // 值域[0,π]
//        System.out.println("∠AOB = " + Math.toDegrees(acos)); // 球心角 值域[0,180]
        return EARTH_RADIUS * acos; // 最终结果
    }

    private List<Double> findNeighPosition(double longitude, double latitude, double distance) {
        //先计算查询点的经纬度范围
        double r = 6371;//地球半径千米
        double dis = distance;//距离
        double dlng = 2 * Math.asin(Math.sin(dis / (2 * r)) / Math.cos(latitude * Math.PI / 180));
        dlng = dlng * 180 / Math.PI;//角度转为弧度
        double dlat = dis / r;
        dlat = dlat * 180 / Math.PI;
        double minlat = latitude - dlat;
        double maxlat = latitude + dlat;
        double minlng = longitude - dlng;
        double maxlng = longitude + dlng;

        return CollUtil.newArrayList(minlat, maxlat, minlng, maxlng);

    }
}
